package cn.remex.core.util.excelutils;

import cn.remex.RemexConstants;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import cn.remex.core.util.FileHelper;
import cn.remex.core.util.Judgment;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.util.*;

/**
 * Created by guoqi on 2016/7/11.
 */
public class ExcelExportUtil {
    private String firstSheetName = "first";
    private String excelFilePatch;
    private File file;
    private Workbook wb = new XSSFWorkbook();
    private Map<String, Sheet> sheetMap = new HashMap<>();
    private Map<String, List<String>> sheetTitles = null;
    private Map<String, Object> titleToLabelMap;


    public ExcelExportUtil(String excelFilePatch,String... sheetNames) {
        Assert.notNullAndEmpty(excelFilePatch, ServiceCode.FAIL, "Excel文件路径为空！");
//        Assert.isTrue(sheetNames != null && sheetNames.length > 0, ServiceCode.FAIL, "Excel文件sheet必须定义");
        file = FileHelper.createFile(excelFilePatch);
        if (sheetNames!=null && sheetNames.length>0 ){
            for (String sheetName : sheetNames) {
                sheetMap.put(sheetName, wb.createSheet(sheetName));
            }
        }else {
            sheetMap.put(firstSheetName, wb.createSheet(firstSheetName));
        }
    }

    //生成file
    public File createExcelFile() {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            wb.write(out);
            out.flush();
        } catch (IOException e) {
            RemexConstants.logger.error("Excel文件生成错误！{}", e);
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }


    //用于持续添加数据。
    public ExcelExportUtil inputDataByList(List<List<Object>> rowsList) {
        Assert.isTrue(sheetTitles != null && sheetTitles.size() > 0, ServiceCode.FAIL, "标题为空请定义标题！");
        Map<String, List<List<Object>>> sheetNameAndRowsMap = new HashMap<>();
        sheetNameAndRowsMap.put(this.getDefaultSheetName(), rowsList);
        this.inputDataByList(sheetTitles, sheetNameAndRowsMap);
        return this;
    }

    //没有指定标题的数据默认第一个sheet
    public ExcelExportUtil inputDataByList(List<String> sheetTitles, List<List<Object>> rowsList) {
        Map<String, List<String>> sheetTitlesMap = new HashMap<>();
        sheetTitlesMap.put(this.getDefaultSheetName(), sheetTitles);
        Map<String, List<List<Object>>> sheetNameAndRowsMap = new HashMap<>();
        sheetNameAndRowsMap.put(this.getDefaultSheetName(), rowsList);
        this.inputDataByList(sheetTitlesMap, sheetNameAndRowsMap);
        return this;
    }

    //数据没有指定标题的时候按照顺序放
    public ExcelExportUtil inputDataByList(Map<String, List<String>> sheetTitles, Map<String, List<List<Object>>> sheetNameAndRowsMap) {
        Assert.isTrue(sheetTitles != null && sheetTitles.size() > 0, ServiceCode.FAIL, "title不能为空！");
        Assert.isTrue(sheetNameAndRowsMap != null && sheetNameAndRowsMap.size() > 0, ServiceCode.FAIL, "数据不能为空！");
        this.sheetTitles = sheetTitles;
        sheetTitles.forEach((s, strings) -> {
            Sheet sheet = sheetMap.get(s);
            Assert.notNull(sheet, ServiceCode.FAIL, "sheet标题错误！");
            List<List<Object>> rowsLists = sheetNameAndRowsMap.get(s);
            int lastRowNum = sheet.getLastRowNum();
            if (lastRowNum == 0) {
                this.createTitle(sheet, strings);
            }
            lastRowNum++;
            for (List<Object> rowData : rowsLists) {
                this.setCellValue(sheet.createRow(lastRowNum), rowData);
                lastRowNum++;
            }
        });
        return this;
    }

    //用于持续添加数据。
    public ExcelExportUtil inputDataBySheet(List<Map<String, Object>> sheetNameAndRows) {
        Assert.isTrue(sheetTitles != null && sheetTitles.size() > 0, ServiceCode.FAIL, "标题为空请定义标题！");
        Map<String, List<Map<String, Object>>> sheetNameAndRowsMap = new HashMap<>();
        sheetNameAndRowsMap.put(this.getDefaultSheetName(), sheetNameAndRows);
        this.inputDataBySheet(sheetTitles, sheetNameAndRowsMap);
        return this;
    }

    //添加数据，不指定sheet。使用默认sheet名字
    public ExcelExportUtil inputDataBySheet(List<String> sheetTitles, List<Map<String, Object>> sheetNameAndRows) {
        Map<String, List<String>> sheetTitlesMap = new HashMap<>();
        sheetTitlesMap.put(this.getDefaultSheetName(), sheetTitles);
        Map<String, List<Map<String, Object>>> sheetNameAndRowsMap = new HashMap<>();
        sheetNameAndRowsMap.put(this.getDefaultSheetName(), sheetNameAndRows);
        this.inputDataBySheet(sheetTitlesMap, sheetNameAndRowsMap);
        return this;
    }

    /**
     * 添加数据，可以持续添加
     *
     * @param sheetTitles      sheetName-&gt;titles
     * @param sheetNameAndRows sheetName-&gt;rows{ title-&gt;field}
     */
    public void inputDataBySheet(Map<String, List<String>> sheetTitles, Map<String, List<Map<String, Object>>> sheetNameAndRows) {
        Assert.isTrue(sheetTitles != null && sheetTitles.size() > 0, ServiceCode.FAIL, "title不能为空！");
        Assert.isTrue(sheetNameAndRows != null && sheetNameAndRows.size() > 0, ServiceCode.FAIL, "数据不能为空！");
        Assert.isTrue(sheetNameAndRows.size() == sheetTitles.size(), ServiceCode.FAIL, "数据和标题的sheet数量不对应！");
        this.sheetTitles = sheetTitles;
        sheetTitles.forEach((s, strings) -> {
            Sheet sheet = sheetMap.get(s);
            Assert.notNull(sheet, ServiceCode.FAIL, "sheet标题错误！");
            List<Map<String, Object>> rows = sheetNameAndRows.get(s);
            Assert.isTrue(rows != null, ServiceCode.FAIL, "数据错误！ sheet找不到！");
            int lastRowNum = sheet.getLastRowNum();
            if (lastRowNum == 0) {
                this.createTitle(sheet, strings);
                lastRowNum++;
            }
            for (Map<String, Object> rowData : rows) {
                this.setCellValue(sheet.createRow(lastRowNum), strings, rowData);
                lastRowNum++;
            }
        });

    }

    //创建标题
    private void createTitle(Sheet sheet, List<String> titles) {
        //创建的标题在第一行
        Row row = sheet.createRow(0);
        for (int i = 0; i < titles.size(); i++) {
            if(this.titleToLabelMap==null || Judgment.nullOrBlank(this.titleToLabelMap.get(titles.get(i)))){
                this.setCellValue(row, i, titles.get(i));
            }else {
                this.setCellValue(row, i, this.titleToLabelMap.get(titles.get(i)));
            }
        }
    }

    public ExcelExportUtil inputLabel(Map<String,Object> titleToLabelMap) {
        this.titleToLabelMap = titleToLabelMap;
        return this;
    }


    private void setCellValue(Row row, List<Object> rowData) {
        for (int i = 0; i < rowData.size(); i++) {
            Object obj = rowData.get(i);
            this.setCellValue(row, i, obj);
        }
    }

    //设置每个单元格，和标题对应
    private void setCellValue(Row row, List<String> titles, Map<String, Object> rowData) {
        for (int i = 0; i < titles.size(); i++) {
            Object obj = rowData.get(titles.get(i));
            this.setCellValue(row, i, obj);
        }
    }

    //每个单元格设置值
    private void setCellValue(Row row, int cellnum, Object value) {
        Cell cell = row.getCell(cellnum);
        if (Judgment.nullOrBlank(cell)) {
            cell = row.createCell(cellnum);
        }
        if (value != null) {
            if (value instanceof String) {
                cell.setCellValue((String) value);
            } else if (value instanceof Boolean) {
                cell.setCellValue((boolean) value);
            } else if (value instanceof Date) {
                cell.setCellValue((Date) value);
            } else if (value instanceof Double ||value instanceof Long || value instanceof Integer) {
                cell.setCellValue(Double.valueOf(value.toString()));
            } else if (value instanceof Calendar) {
                cell.setCellValue((Calendar) value);
            } else {
                throw new Error("没有合适的excel类型！");
            }
        }else{
            String a = null;
            cell.setCellValue(a);
        }
    }

    private String getDefaultSheetName(){
        if(sheetMap.get(firstSheetName)!=null){
            return firstSheetName;
        }else {
            return sheetMap.keySet().stream().findFirst().get();
        }
    }
}
